﻿
namespace Sai.Core.Rules
{
    using System.Linq;
    using Sai.Core.Introspection;
    
    public class CheckTypeConstructors : IClassRule
    {
        public void Validate(ClassDeclaration was, ClassDeclaration isNow, ITypeDifference typeDifference)
        {
            // first we check for added/removed static constructors

            var wasCCtor = was.StaticConstructor;
            var nowCCtor = isNow.StaticConstructor;

            if (wasCCtor == null && nowCCtor != null)
            {
                typeDifference.IdentifiedChange(
                    new UnaryTypeChange(
                        TypeChangeReason.ConstructorAdded,
                        nowCCtor,
                        "Static constructor was added"));
            }
            else if (wasCCtor != null && nowCCtor == null)
            {
                // removed
                typeDifference.IdentifiedChange(
                    new UnaryTypeChange(
                        TypeChangeReason.ConstructorRemoved,
                        wasCCtor,
                        "Static constructor was removed"));
            }

            var wasConstructors = was.InstanceConstructors;
            var nowConstructors = isNow.InstanceConstructors;

            var obsolete = nowConstructors.FindObsoleteMembers();

            foreach (var obs in obsolete)
            {
                typeDifference.IdentifiedChange(
                    new UnaryTypeChange(
                        TypeChangeReason.ConstructorObsolete,
                        obs,
                        obs.ObsoleteReason
                    ));
            }

            var onlyInOld = wasConstructors.RemoveExactMatches(nowConstructors);
            var onlyInNew = nowConstructors.RemoveExactMatches(wasConstructors);

            if (onlyInOld.Count == 1 && onlyInNew.Count == 1)
            {
                // guessing constructor has changed
                InstanceConstructorDeclaration oldCtor = onlyInOld.First();
                InstanceConstructorDeclaration newCtor = onlyInNew.First();

                if (!newCtor.Signature.ExactMatchFor(oldCtor.Signature))
                {
                    typeDifference.IdentifiedChange(
                    new BinaryTypeChange(
                        TypeChangeReason.ConstructorChanged,
                        oldCtor,
                        newCtor,
                        "Constructor signature changed"
                    ));
                }
            }
            else
            {
                // otherwise we just report which ones have been 
                // removed and which ones have been added.
                if (onlyInOld.Any())
                {
                    foreach (var remove in onlyInOld)
                    {
                        typeDifference.IdentifiedChange(
                            new UnaryTypeChange(
                                TypeChangeReason.ConstructorRemoved,
                                remove
                            ));
                    }
                }


                if (onlyInNew.Any())
                {
                    foreach (var add in onlyInNew)
                    {
                        typeDifference.IdentifiedChange(
                            new UnaryTypeChange(
                                TypeChangeReason.ConstructorAdded,
                                add
                            ));
                    }
                }
            }
        }
    }
}
